package ecode

import (
	"github.com/pkg/errors"
)

var (
// _localizedMessage atomic.Value // NOTE: map[int]map[string]string
// _messages sync.Map // NOTE: stored map[string]map[int]string
)

// Register register ecode message map.
// Deprecated
/*func Register(codes map[int]map[string]string) {
	cm := make(map[int]string, len(codes))
	for id, messages := range codes {
		if msg, ok := messages[LangDefault]; ok {
			cm[id] = msg
		}
	}
	_messages.Store(cm)
	_localizedMessage.Store(codes)
}*/

/*// Init add code and msg to global variable
func Init(code int, msg string) *Code {
	//_messages.Store(code, msg)
	return New(code, msg)
}
*/

// New an ecode.Codes by int value.
// NOTE: ecode must unique in global, the New will check repeat and then panic.
func New(code int, message string) *Code {
	return &Code{
		code:    code,
		message: message,
	}
}

// Codes ecode error interface which has a code & message.
type Codes interface {
	// Error return Code in string form
	// NOTE: don't use Error in monitor report even it also work for now
	Error() string
	// Code get error code.
	Code() int
	// Message get code message.
	Message() string
	//Details get error detail,it may be nil.
	Details() []interface{}
	// Equal for compatible.
	// Deprecated: please use ecode.EqualError.
	Equal(error) bool
	//Wrap wrap error
	Wrap(string) error
}

// A Code is an int error code spec.
type Code struct {
	code    int
	message string
}

func (e Code) Error() string {
	return e.message
}

// Code return error code
func (e Code) Code() int {
	return e.code
}

// Message return error message
func (e Code) Message() string {
	/*if v, ok := _messages.Load(e.Code()); ok {
		return v.(string)
	}
	return e.Error()*/
	return e.message
}

// Details return details.
func (e Code) Details() []interface{} { return nil }

// Equal for compatible.
// Deprecated: please use ecode.EqualError.
func (e *Code) Equal(err error) bool { return EqualError(e, err) }

func (e *Code) Wrap(err string) error {
	return &Code{
		code:    e.code,
		message: e.message + " : " + err,
	}
}

// Int parse code int to error.
//func Int(i int) Code { return Code(i) }

// ToCode parse code string to error.
func ToCode(e string) Codes {
	if e == "" {
		return OK
	}
	return &Code{
		code:    -1,
		message: e,
	}
}

// Cause from error to ecode.
func Cause(e error) Codes {
	if e == nil {
		return OK
	}
	ec, ok := errors.Cause(e).(Codes)
	if ok {
		return ec
	}
	return ToCode(e.Error())
}

// Equal equal a and b by code int.
func Equal(a, b Codes) bool {
	if a == nil {
		a = OK
	}
	if b == nil {
		b = OK
	}
	return a.Code() == b.Code()
}

// EqualError equal error
func EqualError(code Codes, err error) bool {
	return Cause(err).Code() == code.Code()
}
